package br.com.damazzy.util {
	
	import mx.collections.ArrayCollection;
	import mx.utils.ObjectUtil;
	
	public class DateUtils {
		
		public static const COMPARA_DATA_NIVEL_DATA:int = 0;
		public static const COMPARA_DATA_NIVEL_DATA_HORA:int = 1;
		public static const COMPARA_DATA_NIVEL_DATA_HORA_MINUTO:int = 2;
		public static const COMPARA_DATA_NIVEL_DATA_HORA_MINUTO_SEGUNDO:int = 3;
		public static const COMPARA_DATA_NIVEL_DATA_HORA_MINUTO_SEGUNDO_MILISSEGUNDO:int = 4;
		
		private static var necessitaTratarBugData:Boolean = false;
		private static var contextoTimeZoneVerificado:Boolean = false;
		
		public static function get MENOR_DATA():Date {
			var menorData:Date = new Date(1, 0);
			menorData.setFullYear(1, 0, 1);
			
			return menorData;
		}
		
		public static function equals(dt1:Date, dt2:Date, nivel:int=COMPARA_DATA_NIVEL_DATA):Boolean {
			var retorno:Boolean = false;
			
			if(dt1 == null && dt1 == null) {
				return true;
			}else if(dt1 == null && dt2 != null) {
				return false;
			}else if(dt1 != null && dt2 == null) {
				return false;
			}
			
			switch(nivel) {
				case COMPARA_DATA_NIVEL_DATA:
					retorno = (dt1.fullYear == dt2.fullYear && 
							   dt1.month == dt2.month && 
							   dt1.date == dt2.date);
					break;
					
				case COMPARA_DATA_NIVEL_DATA_HORA:
					retorno = (dt1.fullYear == dt2.fullYear && 
							   dt1.month == dt2.month && 
							   dt1.date == dt2.date &&
							   dt1.hours == dt2.hours);
					break;
				case COMPARA_DATA_NIVEL_DATA_HORA_MINUTO:
					retorno = (dt1.fullYear == dt2.fullYear && 
							   dt1.month == dt2.month && 
							   dt1.date == dt2.date &&
							   dt1.hours == dt2.hours &&
							   dt1.minutes == dt2.minutes);
					break;
				case COMPARA_DATA_NIVEL_DATA_HORA_MINUTO_SEGUNDO:
					retorno = (dt1.fullYear == dt2.fullYear && 
							   dt1.month == dt2.month && 
							   dt1.date == dt2.date &&
							   dt1.hours == dt2.hours &&
							   dt1.minutes == dt2.minutes &&
							   dt1.seconds == dt2.seconds);
					break;
				case COMPARA_DATA_NIVEL_DATA_HORA_MINUTO_SEGUNDO_MILISSEGUNDO:
					retorno = (dt1.fullYear == dt2.fullYear && 
							   dt1.month == dt2.month && 
							   dt1.date == dt2.date &&
							   dt1.hours == dt2.hours &&
							   dt1.minutes == dt2.minutes &&
							   dt1.seconds == dt2.seconds &&
							   dt1.milliseconds == dt2.milliseconds);
					break;
			}
			
			return retorno;
		}
		
	    /**
	     *  Quebra a String que contem a data, e retorna como um objeto Date
	     *  O argumento <code>inputFormat</code> contém o formato da data
	     *  no argumento <code>valueString</code>.
	     *  O formato somente pode conter <code>"M"</code>,<code>"D"</code>,<code>"Y"</code>,
	     *  informando o Mês, Dia, Ano em qualquer ordem.
	     *
	     *  A função não verificar a validade da data, caso seja um valor inválido será retornado null
	     *
	     *  @param valueString Valor da Data.
	     *
	     *  @param inputFormat Formato da data.
	     *
	     *  @return O data string em um objeto Date.
	     *
	     *  @example
	     *  <pre>var dob:Date = DateField.stringToDate("06/30/2005", "MM/DD/YYYY");</pre>
	     */
	    public static function stringToDate(valueString:String, inputFormat:String):Date
	    {
			
			if(StringUtils.trim(valueString) == ""){
				return null;
			}
			
	        var mask:String
	        var temp:String;
	        var dateString:String = "";
	        var monthString:String = "";
	        var yearString:String = "";
	        var j:int = 0;
			
	        var n:int = inputFormat.length;
	        for (var i:int = 0; i < n; i++,j++)
	        {
	            temp = "" + valueString.charAt(j);
	            mask = "" + inputFormat.charAt(i);
	
	            if (mask == "M")
	            {
	                if (isNaN(Number(temp)) || temp == " ")
	                    j--;
	                else
	                    monthString += temp;
	            }
	            else if (mask == "D")
	            {
	                if (isNaN(Number(temp)) || temp == " ")
	                    j--;
	                else
	                    dateString += temp;
	            }
	            else if (mask == "Y")
	            {
	                yearString += temp;
	            }
	            else if (!isNaN(Number(temp)) && temp != " ")
	            {
	                return null;
	            }
	        }
	
	        temp = "" + valueString.charAt(inputFormat.length - i + j);
	        if (!(temp == "") && (temp != " "))
	            return null;
	
	        var monthNum:Number = Number(monthString);
	        var dayNum:Number = Number(dateString);
	        var yearNum:Number = Number(yearString);
	
	        if (isNaN(yearNum) || isNaN(monthNum) || isNaN(dayNum))
	            return null;
	
	        if (yearString.length == 2 && yearNum < 70)
	            yearNum+=2000;
	
	        var newDate:Date = new Date(yearNum, monthNum - 1, (dayNum == 0 ? 1 : dayNum));
	
	        return newDate;
	    }
	    
		/**
		 * Tranforma uma data do locale corrente para o formato UTC
		 */		
		public static function getDataUTC(data: Date): Date {
			if (data == null) {
				return null;
			}
			
		    var dateUTC:Date = new Date(data.valueOf() - (data.getTimezoneOffset() * 60000));
		    
		    return dateUTC;
		}
		
		/**
		 * Tranforma uma data do locale corrente para o formato UTC
		 */		
		public static function getData(dataUTC: Date): Date {
			if (dataUTC == null) {
				return null;
			}
			
		    var data:Date = new Date(dataUTC.valueOf() + (dataUTC.getTimezoneOffset() * 60000));
			
/*			return new Date(dataUTC.fullYearUTC, dataUTC.monthUTC, dataUTC.dateUTC,
				dataUTC.hoursUTC, dataUTC.minutesUTC, dataUTC.secondsUTC,
				dataUTC.millisecondsUTC);*/
		    
		    return data;
		}
		
		/**
		 * Método pega os milissegundos sem considerar fuso local de uma data informada
		 * 
		 * @param value Data de onde recuperar os milissegundos
		 * 
		 * @return retorna milissegundos sem considerar fuso local
		 */
		public static function getUTCMilliseconds(value:Date):Number {
			
			if(value == null){
				return 0;
			}
			
			return value.valueOf() - (value.getTimezoneOffset() * 60000);
			
		}
		
		/**
		 * Pega data com fuso local a partir de valor em milissegundos UTC informado
		 * 
		 * @param value valor em milissegundos em UTC 
		 *  
		 * @return Data com fuso local
		 */		
		public static function getDateFromUTCMilliseconds(value:Number):Date {
			if(isNaN(value)) {
				return null;
			}
			
			var dateUTC:Date = new Date(value);
			
			return new Date(dateUTC.fullYearUTC, dateUTC.monthUTC, dateUTC.dateUTC,
				dateUTC.hoursUTC, dateUTC.minutesUTC, dateUTC.secondsUTC,
				dateUTC.millisecondsUTC);
		}
		
		private static function verificarNecessidadeTratamentoData():Boolean {
			//se nas datas abaixo temos fuso-horários diferentes 
			//deduzimos que a opção de ajustar automaticamente ao
			//horário de verão está marcado e (claro) temos horário de verão
			if(!contextoTimeZoneVerificado){
				necessitaTratarBugData = new Date(2010, 11, 1).getTimezoneOffset() != 
										 new Date(2010, 6, 1).getTimezoneOffset();
				contextoTimeZoneVerificado = true;
			}
			
			return necessitaTratarBugData; 
		}
		
		public static function tratarBugData(data:Date):Date 
		{
			if(data == null){
				return data;
			}			
			
			if(!verificarNecessidadeTratamentoData()){
				return data;
			}
			
			//verifica se estamos em TimeZone onde é possível ocorrer o problema
			if(data.getTimezoneOffset() != 180)
			{
				return data;
			}
			
			if(data.month != 9 || data.day != 6 || 
				data.hours != 23 || data.minutes != 0 || 
				data.seconds != 0 || data.date < 13) {
				
				return data;
			}
			
			var primeiroDomingo:int = new Date(data.fullYear, 9, 1).day;
			
			var terceiroDomingo:int = new Date(data.fullYear, 9, 21 - primeiroDomingo, 12).date;
			
			if(data.date != terceiroDomingo){
				return  data;
			}
			
			return new Date(data.fullYear, data.month, data.date + 1, 1);
		}
        
	}
}